/*
 * wrapper.c
 *
 *
 * A suid wrapper that sets effective userid based on the REMOTE_USER
 * environment variable.  Fails if the real user is not the one under
 * whom the webserver runs.
 *
 * $Log: wrapper.c,v $
 * Revision 1.1  2001/10/04 21:06:05  bduggan
 * Initial revision
 *
 * Revision 1.4  2001/07/09 19:46:12  bduggan
 * changed to use primary gid
 * if user is not in group
 *
 * Revision 1.3  2001/07/09 19:21:43  bduggan
 * added rcs log to header
 * 
 * revision 1.2
 * date: 2001/07/09 19:21:19;   bduggan; 
 * added setgid functionality
 * 
 * revision 1.1
 * date: 2001/01/15 11:56:45 EST 2001
 * Initial revision
 *
 */

/* WEB_USER should be the user under whom the webserver daemons run -- e.g. "noweb", "nobody"*/
#define WEB_USER "apache" 

/* PROGRAM_NAME should be the program for which this is a wrapper. */
#define PROGRAM_NAME "/var/www/html/rcsweb-dev/rcsweb.pl"   

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <errno.h>
#include <pwd.h>
#include <grp.h>

int
main(int argc, char * const argv[], char* const envp[])
{
 uid_t nobody_id;   /* user id for nobody */
 uid_t remote_user_id;
 gid_t remote_user_gid;
 struct passwd* nobody_struct;
 struct passwd* remote_user_struct;
 char *remote_user;
 int ret_val;

 /* Get nobody's info */
 nobody_struct = getpwnam(WEB_USER);
 if (!nobody_struct) {
    fprintf (stderr,"Couldn't find user %s.\n",WEB_USER);
    exit(1);
 }
 nobody_id = nobody_struct->pw_uid;

 if (getuid()!=nobody_id) {
    fprintf(stderr,"Only %s can run this program.\n",WEB_USER);
    exit(1);
 }

 /* Get remote_user's info */
 remote_user = getenv("REMOTE_USER");
 if (!remote_user) {
    fprintf(stderr,"Couldn't get remote user information.\n");
    exit(1);
 }

 remote_user_struct = getpwnam(remote_user);
 if (!remote_user_struct) {
    fprintf (stderr,"Couldn't find user %s.\n",remote_user);
    exit(1);
 }
 remote_user_id = remote_user_struct->pw_uid;

 /* Initialize group permissioning.  */
 if (initgroups(remote_user,remote_user_struct->pw_gid)==-1) {
    fprintf(stderr,"An error occurred while calling initgroups.  Errno: %d\n",errno);
    exit(1);
 }

 /* Set the group id */
 if (setgid(remote_user_struct->pw_gid)==-1) {
    fprintf(stderr,"An error occurred while calling setgid.  Errno: %d\n",errno);
    exit(1);
 }

 /* Now set the uid. */
 if (setuid(remote_user_id)!=0) {
    fprintf(stderr,"An error occurred while calling setuid.  Errno: %d\n",errno);
    exit(1);
 }

 if (execve(PROGRAM_NAME,0,envp)==-1) {
    fprintf(stderr,"Error executing %s.  errno: %d\n",PROGRAM_NAME,errno);    
    exit(1);
 };

}
